﻿using SharpDX;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using D3D = SharpDX.Direct3D;
using D3D11 = SharpDX.Direct3D11;
using DXGI = SharpDX.DXGI;

// Die Elementvorlage "Leere Seite" ist unter http://go.microsoft.com/fwlink/?LinkId=234238 dokumentiert.

namespace UniversalApp
{
    /// <summary>
    /// Eine leere Seite, die eigenständig verwendet werden kann oder auf die innerhalb eines Frames navigiert werden kann.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        #region Private Fields

        private D3D11.Resource backBufferTexture;
        private D3D11.RenderTargetView backBufferView;
        private D3D11.Device2 device;
        private D3D11.DeviceContext2 deviceContext;
        private DXGI.SwapChain2 swapChain;

        #endregion Private Fields

        #region Public Constructors

        public MainPage()
        {
            this.InitializeComponent();
        }

        #endregion Public Constructors

        #region Private Methods

        private void CompositionTarget_Rendering(object sender, object e)
        {
            // Set the active back buffer and clear it.
            this.deviceContext.OutputMerger.SetRenderTargets(this.backBufferView);
            this.deviceContext.ClearRenderTargetView(this.backBufferView, Color.CornflowerBlue);
            // Tell the swap chain to present the buffer.
            this.swapChain.Present(1, DXGI.PresentFlags.None, new DXGI.PresentParameters());
        }

        private void SwapChainPanel_Loaded(object sender, RoutedEventArgs e)
        {
            using (D3D11.Device defaultDevice = new D3D11.Device(D3D.DriverType.Hardware, D3D11.DeviceCreationFlags.Debug))
            {
                this.device = defaultDevice.QueryInterface<D3D11.Device2>();
            }

            this.deviceContext = this.device.ImmediateContext2;

            float pixelScale = Windows.Graphics.Display.DisplayInformation.GetForCurrentView().LogicalDpi / 96.0f;

            //Create Swap chain
            DXGI.SwapChainDescription1 swapChainDescription = new DXGI.SwapChainDescription1()
            {
                // No transparency.
                AlphaMode = DXGI.AlphaMode.Ignore,
                // Double buffer.
                BufferCount = 2,
                // BGRA 32bit pixel format.
                Format = DXGI.Format.B8G8R8A8_UNorm,
                // Unlike in CoreWindow swap chains, the dimensions must be set.
                Height = (int)(this.SwapChainPanel.RenderSize.Height * pixelScale),
                Width = (int)(this.SwapChainPanel.RenderSize.Width * pixelScale),
                // Default multisampling.
                SampleDescription = new DXGI.SampleDescription(1, 0),
                // In case the control is resized, stretch the swap chain accordingly.
                Scaling = DXGI.Scaling.Stretch,
                // No support for stereo display.
                Stereo = false,
                // Sequential displaying for double buffering.
                SwapEffect = DXGI.SwapEffect.FlipSequential,
                // This swapchain is going to be used as the back buffer.
                Usage = DXGI.Usage.BackBuffer | DXGI.Usage.RenderTargetOutput,
            };

            // Obtain the automatically created SharpDX.DXGI.Factory3 by queriying the Direct3D
            // device for the SharpDX.DXGI.Device3 interface, and obtaining the reference to its
            // parent. Use it to create the swap chain and then cast it to SwapChain2.

            using (DXGI.Device3 dxgiDevice3 = this.device.QueryInterface<DXGI.Device3>())
            {
                // Get the DXGI factory automatically created when initializing the Direct3D device.
                using (DXGI.Factory3 dxgiFactory3 = dxgiDevice3.Adapter.GetParent<DXGI.Factory3>())
                {
                    // Create the swap chain and get the highest version available.
                    DXGI.SwapChain1 swapChain1 = new DXGI.SwapChain1(dxgiFactory3, this.device, ref swapChainDescription);
                    this.swapChain = swapChain1.QueryInterface<DXGI.SwapChain2>();
                }
            }

            // Obtain the *SharpDX.DXGI.ISwapChainPanelNative reference and set its swap chain:
            using (DXGI.ISwapChainPanelNative nativeObject = ComObject.As<DXGI.ISwapChainPanelNative>(this.SwapChainPanel))
            {
                // Set its swap chain.
                nativeObject.SwapChain = this.swapChain;
            }

            // Finally, obtain a SharpDX.Direct3D11.Texture2D from the front buffer of the swap chain
            // and create a SharpDX.Direct3D11.RenderTargetView with it so it can be set as the back
            // buffer when drawing:
            this.backBufferTexture = D3D11.Texture2D.FromSwapChain<D3D11.Texture2D>(this.swapChain, 0);
            this.backBufferView = new D3D11.RenderTargetView(this.device, this.backBufferTexture);

            // And, for now, we are only going to clear the backbuffer to a solid color and present it:
            CompositionTarget.Rendering += CompositionTarget_Rendering;
        }

        #endregion Private Methods
    }
}